package com.chensi.admin.web.aspect;

import com.chensi.admin.web.common.BaseErrorCode;
import com.chensi.admin.web.common.JsonResult;
import com.chensi.admin.web.exception.BaseException;
import com.chensi.admin.web.exception.ItemNotFoundException;
import com.chensi.admin.web.exception.ItemRepeatException;
import com.chensi.admin.web.exception.NotLoginException;
import com.netflix.hystrix.exception.HystrixRuntimeException;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.util.Optional;

import static com.chensi.admin.web.common.BaseErrorCode.*;


/**
 * @author si.chen
 */
@ControllerAdvice
@ResponseBody
@Slf4j
public class ExceptionAspect {

    @ExceptionHandler(BindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public JsonResult handleConstraintViolationException(BindException e) {
        BindingResult result = e.getBindingResult();
        return toJsonResult(result);
    }

    @ExceptionHandler(BaseException.class)
    @ResponseStatus(HttpStatus.OK)
    public JsonResult handleBaseException(BaseException e) {
        return JsonResult.failed(e.getErrorCode(), e.getErrorMessage(), e.getMessage());
    }

    @ExceptionHandler(HystrixRuntimeException.class)
    @ResponseStatus(HttpStatus.OK)
    public JsonResult handleHystrixException(HystrixRuntimeException e) {
        log.error("Feign调用失败，远程服务不可用");
        return JsonResult.failed(HYSTRIX_ERROR.getCode(), HYSTRIX_ERROR.getMessage(), e.getMessage());
    }

    /**
     * 所有其它异常
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public JsonResult handleException(Exception e) {
        log.error("handler exception", e);
        e.printStackTrace();
        return JsonResult.failed(BaseErrorCode.UNKNOWN_ERROR, e.getMessage());
    }

    @ExceptionHandler(ItemNotFoundException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public JsonResult handleItemNotFoundException(ItemNotFoundException e) {
        return JsonResult.failed(e.getErrorCode(), e.getErrorMessage(), e.getMessage());
    }

    @ExceptionHandler(NotLoginException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public JsonResult handleNotLoginException(NotLoginException e) {
        return JsonResult.failed(e.getErrorCode(), e.getErrorMessage(), e.getMessage());
    }

    @ExceptionHandler(UnauthorizedException.class)
    @ResponseStatus(HttpStatus.OK)
    public JsonResult handleAuthenticationException(UnauthorizedException e) {
        return JsonResult.failed(UNAUTHORIZED, e.getMessage());
    }

    @ExceptionHandler(AuthenticationException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public JsonResult handleAuthenticationException(AuthenticationException e) {
        log.error("handler exception", e);
        return JsonResult.failed(AUTH_ERROR, e.getMessage());
    }

    @ExceptionHandler(ItemRepeatException.class)
    @ResponseStatus(HttpStatus.CONFLICT)
    public JsonResult handleItemRepeatException(ItemRepeatException e) {
        return JsonResult.failed(e.getErrorCode(), e.getErrorMessage(), e.getMessage());
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public JsonResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        BindingResult result = e.getBindingResult();
        return toJsonResult(result);
    }

    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public JsonResult handleIllegalArgumentException(IllegalArgumentException e) {
        log.error("handler exception", e);
        return JsonResult.failed(INVALID_PARAMETERS.getCode(), e.getMessage());
    }

    private JsonResult toJsonResult(BindingResult result) {
        FieldError fieldError = result.getFieldError();
        String desc = Optional.ofNullable(fieldError).map(FieldError::getDefaultMessage).orElse(null);
        return JsonResult.failed(INVALID_PARAMETERS.getCode(), desc);
    }
}
